//
// Created by lvyer on 2021/11/29.
//

#include <common/RendererFilter.h>

RendererFilter::RendererFilter() {

}

RendererFilter::~RendererFilter() {

}

//初始化着色器小程序 并编译着色器代码 并链接
void RendererFilter::initFilter() {
    char vShaderStr[] =
            "#version 300 es                          \n"
            "layout(location = 0) in vec4 vPosition;  \n"
            "void main()                              \n"
            "{                                        \n"
            "   gl_Position = vPosition;              \n"
            "gl_PointSize = 50.0; \n"
            "}                                        \n";

    char fShaderStr[] =
            "#version 300 es                              \n"
            "precision mediump float;                     \n"
            "out vec4 fragColor;                          \n"
            "void main()                                  \n"
            "{                                            \n"
            "   fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 );  \n"
            "}                                            \n";
    m_ProgramObj = GLTools::createProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);

    // 通过id通知GPU 我们要使用这个着色器程序了
    glUseProgram(m_ProgramObj);
    GLfloat vertices[] = {0.0f, 0.5f,
                          -0.5f, -0.5f,
                          0.5f, -0.5f
    };
    unsigned int indices[] = {
            0, 1, 3, // first triangle
            1, 2, 3  // second triangle
    };

    //初始化创建 VBO  VAO  EBO 对象
    glGenVertexArrays(1, &VAO);
    glGenBuffers(1, &VBO);
    glGenBuffers(1, &EBO);

    //为当前使用的着色器程序绑定VAO 顶点缓冲数组对象
    glBindVertexArray(VAO);
    //为当前绑定 顶点缓冲对象
    glBindBuffer(GL_ARRAY_BUFFER, VBO);
    //为当前已绑定的缓冲对象填充数据
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    // 为顶点着色器的 0号变量赋值
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void *) 0);
    glEnableVertexAttribArray(0);
}

void RendererFilter::changerFilter(int width, int height) {
    this->width = width;
    this->height = height;
    glViewport(0, 0, width, height);
    createFrameBufferObj(width, height);
}

int RendererFilter::drawFilter(int textureId) {
    if (m_ProgramObj == 0)
        return -1;
    //清除上次渲染内容
    glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glClearColor(1.0, 1.0, 1.0, 1.0);

    glUseProgram(m_ProgramObj);
    //绑定当前FBO
    glBindFramebuffer(GL_FRAMEBUFFER, m_FboId);
    glBindVertexArray(VAO);
    if (textureId > 0) {
        //如果起始纹理id存在，则将其渲染
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textureId);
    }
    //正式将纹理和数据渲染到FBO中，最终会绘制到与之绑定的纹理id中
    glDrawArrays(GL_TRIANGLES, 0, 3);

    //解绑操作
    glBindVertexArray(0);
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    //返回与FBO绑定的纹理id  颜色附着点
    return m_FboTextureId;
}

bool RendererFilter::createFrameBufferObj(int width, int height) {
    // 创建并初始化 FBO 纹理
    glGenTextures(1, &m_FboTextureId);
    glBindTexture(GL_TEXTURE_2D, m_FboTextureId);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, GL_NONE);

    // 创建并初始化 FBO
    glGenFramebuffers(1, &m_FboId);
    glBindFramebuffer(GL_FRAMEBUFFER, m_FboId);
    glBindTexture(GL_TEXTURE_2D, m_FboTextureId);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_FboTextureId, 0);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
                 GL_UNSIGNED_BYTE, nullptr);
    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        return false;
    }
    glBindTexture(GL_TEXTURE_2D, GL_NONE);
    glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
    return true;
}
